ArmBob v.1.02 Tutorial 3                               GCW 06/06/94

Accounts   2
------------
Now we look at !Account.!RunImage. In main, the variable 'account_no' is
used to count the number of accounts that have been created. The
maximum is given by the variable 'enough'. The statement

                    client = newvector(enough);

creates a vector called 'client' with enough components. The term
"vector" is used, rather than "array", for two reasons. First,arrays 
in Basic, C, Pascal, etc are homogeneous - all their components must 
have the same type. Vectors are inhomogeneous - their components
can have quite different types. Second, one is often tempted to think
of arrays as occupying a sequential block of memory. This would be
misleading for vectors. Strings in ArmBob are closer to arrays in this
sense. In fact vectors correspond more closely with structs of pointers
in C, or with records in Pascal.

The components of an n-component vector v are denoted

              v[0], v[1], .... v[n-1]    

It is legitimate for a vector to be a component of itself! When a vector
is first created, its components all have the value nil.

The components of client are to be the instance objects of the class
account. The function 'banner' informs the user of the services that the
Toy Town Bank can offer. It produces the output

          Welcome to the Toy Town Bank.

             0 Quit
             1 Open an account
             2 Make a withdrawal or deposit
             3 Get a statement
             4 Change your password

          Press one of the above numbers then press RETURN.

Then follows the main loop of the program

 while ((i = input()) != "0")         /* Top level interaction loop */
 { ...... }

which gets input from the user with the function 'input', and responds
accordingly with a switch statement. Those new to C should realise
that in C, and ArmBob, assignments, like

                      i = input()

are actually expressions, which return a value as well as produce a
side-effect, and so this value can be part of a larger expression

                  (i = input()) != "0"

This is not the case in Basic. Remember that Basic uses '=' with two
meanings - assignment and test for equality. In C, and ArmBob, these
two uses are distinguished. Assignment uses '=', test for equality uses
'=='. Another catch for the Basic programmer unused to C lurks in
the switch statement. In Basic's CASE ... WHEN .... ENDCASE construction
execution automatically jumps to after the ENDCASE from the end of
the code following a WHEN condition. On the other hand in C's, and 
ArmBob's, switch (..){ .... case .... } construction, execution does
NOT automatically jump to after the closing brace, unless specifically
directed to do so with a 'break;' statement. Forgetting the 'break;'
is a frequent source of error.

The switch statement in main is used to dispatch execution to various
alternative functions, the first of which is new_account. Note the line

                amount = val(input());

The 'input' function always produces a string. The function 'val' 
converts a string to a number, as far as possible. The next line

       client[account_no++] = new account(amount,name);

uses the post-increment operator '++'. This is an example of a unary
assignment operator. The effect of this one line is equivalent to

       client[account_no] = new account(amount,name);
       account_no = account_no + 1;

The vector 'client' is being used to store all the accounts in a single
structure.

Note that we have functions 'withdraw', 'statement', 'change_password'
despite the fact that these are names of methods for the 'account'
class. There is no clash, because methods are private to the class
they belong to. All these functions use the function 'get_account'
which uses the 'has_owner' method to find which accounts, if any, have
an owner 'name'. It returns 'the_account', so that the operator

           client[the_account]->

can be applied to the appropriate method to do what has been requested.

The heart of get_account is the search for the account owned by 'name':

 while ((the_account<account_no)
        && !(client[the_account]->has_owner(name)))
    the_account++;

The && operator corresponds to Basic's AND, but it has an important
advantage - it is lazy! Compare these two programs, the first in Basic,
the second in ArmBob.

The Basic version:

          REM AND is strict
          IF FNf AND FNg THEN PRINT "yes" ELSE PRINT "no"
          END

          DEF FNf
          PRINT "<<Evaluating f>>"
          = 0

          DEF FNg
          PRINT "<<Evaluating g>>"
          = 0

The ArmBob version:

          /* && is NOT strict */
          main()
          {
           if ( f() && g() ) print("yes\n");
           else print("no\n");
           }

           f()
           {
            print("<<Evaluating f>>\n");
            return 0;
           }

           g()
           {
            print("<<Evaluating g>>\n");
            return 0;
           }

The Basic program produces as output

          <<Evaluating f>>
          <<Evaluating g>>
          no

whereas the ArmBob program produces

          <<Evaluating f>>
          no
          
In other words, && does not bother to evaluate its right hand argument
when it finds that its left hand argument is zero, whereas AND always
evaluates both. This is smart of && and dumb of AND because you often
need, as here in get_account, to test two conditions where error-free
evaluation of the second condition is contingent upon the success of
the first condition. This usually happens with vectors or arrays, where
the first condition checks that an index lies within its bounds, and
if it is, the second condition checks some expression involving the 
component given by the index.

In the same way C's and ArmBob's || is lazy where Basic's OR is strict.
If the left hand argument of || is true, the right hand argument does
not get evaluated.

